(function(){
    /**
     * 泛型使用作用：在不明确数据类型的时候，使用占位符代替
     * 泛型与any相同点：在定义的时候，不明确数据的类型
     * 泛型与any的不同点：
     *      - any会关闭数据类型的校验功能，这样就失去了TS的校验数据类型的效果;
     *        也不能明确参数的类型与返回数据类型一致；
     *      - 泛型能够在调用传递参数的，可以对数据类型进行设置；
     *        也可以明确参数类型与返回类型一致
     */

    /**
     * 1. 泛型的基本定义
     * T代表的是我们要传的类型
     * @param name 
     * @returns 
     */
    function fn1 <T>(name:T):T{
        return name
    }
    // 使用方式一：直接调用，采用的TS的数据类型推断
    let n1 = fn1("李白")
    // 数据n1 = 李白;类型是 = string
    console.log(`数据n1 = ${n1};类型是 = ${typeof n1}`) 

    // 使用方式二：指定泛型的类型
    let n2 = fn1<number>(3)
    // 数据n2 = 3;类型是 = number
    console.log(`数据n2 = ${n2};类型是 = ${typeof n2}`) 


    // 2. 同时定义多个泛型
    function fn2 <T,K>(name:T,age:K):T{
        return name
    }
    let n3 = fn2<string,number>("老王",20)
    // 数据n3 = 老王;类型是 = string
   console.log(`数据n3 = ${n3};类型是 = ${typeof n3}`) 

   // 3. T extends interface
   interface LenghtInter {
       length:number
   }
   //要求参数的length数据类型是number
  function fn3<T extends LenghtInter>(data:T):number{
       return data.length
   }
   fn3([1])

   // 4. 类实现泛型
   class MyClass<T> {
       name: T;
       constructor(name:T) {
           this.name = name;
       }
   }
   const man = new MyClass("隔壁老王")
   // 数据man = 隔壁老王;类型是 = string
   console.log(`数据man = ${man.name};类型是 = ${typeof man.name}`) 

})()